/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.logic;

import com.entity.ConfigFile;
import com.entity.Host;
import com.entity.Service;
import com.utils.SSHManager;
import com.utils.XMLParser;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Esta clase provee metodos para la administracion remota de un host dentro del
 * clúster
 *
 * @author Alejandro Malaver
 */
public class HostAdmin {

    //host que se va a administrar
    private Host host;
    public static HostAdmin instance;

    /**
     *
     * Constructor de la clase, Se usa el patron singleton para crear una unica
     * instancia de la clase.
     *
     */
    private HostAdmin() {
        SSHManager.getInstance().setPassword("123456");
        SSHManager.getInstance().setUserName("root");
    }

    /**
     * obtiene la estancia unica de la clase
     *
     * @return HostAdmin instancia de la clase
     */
    public static HostAdmin getInstance() {
        if (instance == null) {
            instance = new HostAdmin();
        }
        return instance;
    }

    /**
     * reinicia el host remoto.
     *
     */
    public void restartHost() {
        ArrayList<String> tmp = new ArrayList<String>();
        tmp.add("reboot");
        SSHManager.getInstance().execute(tmp);
    }

    /**
     * Ejecuta una serie de comandos en el host remoto y retorna la salida de
     * los mismos.
     *
     * @param commands lista que contiene los comandos a ejecutar
     * @return cadena que contiene la salida de los comandos.
     */
    public String executeCommand(ArrayList<String> commands) {
        String result;
        result = SSHManager.getInstance().execute(commands);
        return result;
    }

    /**
     * Ejecuta comandos de administracion de un demonio especifico en el host
     * remoto y retorna la salida de los mismos.
     *
     * @param signal tipo de comando que se ejecutara: 0:parar, 1: iniciar,
     * 2:reiniciar
     * @return cadena que contiene la salida de los comandos.
     */
    public String adminDaemon(int signal, int index) {

        Service service = host.getServiceList().get(index);
        ArrayList<String> com = new ArrayList<String>();

        switch (signal) {
            case 0:
                com.add(service.getStopCommand());
                break;
            case 1:
                com.add(service.getStartCommand());
                break;
            case 2:
                com.add(service.getRestartCommand());
                break;
        }
        return executeCommand(com);
    }

    /**
     * Ejecuta el comando para conocer el estado de un demonio en el host remoto
     * y retorna la salida del comando.
     *
     * @param statusCommand lista que contiene como unico comando el comando de
     * estado del demonio
     * @return cadena que contiene la salida del comando.
     */
    public String getDaemonStatus(ArrayList<String> statusCommand) {

        String result = executeCommand(statusCommand);
        result = result.contains("pid") ? "Ejecutando" : "Parado";

        if (!result.contains("Ejecutando") && !result.contains("Parado")) {
            if (result.contains("desconocido") || result.contains("unkown")) {
                result = "Desconocido";
            } else {
                result = "Sin Conexión";
            }
        }
        return result;
    }

    /**
     * Retorna el host que se está administrando.
     *
     * @return objeto de tipo Host que que se esta administrando.
     */
    public Host getHost() {
        return host;
    }

    /**
     * Establece el host que se administrará.
     *
     * @param host nuevo host a administrar.
     */
    public void setHost(Host host) {
        this.host = host;
        SSHManager.getInstance().setHost(host.getHostName());
    }

    /**
     * Retorna la lista de demonios del host que se está administrando.
     *
     * @return ArrayList que almacena la lista de demonios del host.
     */
    public ArrayList<Service> getHostServices() {
        return host.getServiceList();
    }

    /**
     * Retorna la lista de archivos de configuracion del host que se está
     * administrando.
     *
     * @return ArrayList que almacena la lista de archivos del host.
     */
    public ArrayList<ConfigFile> getHostFiles() {
        return host.getFileList();
    }

    /**
     * metodo con parametros opcionales que almacena un nuevo item en la lista
     * de demonios o de archivos del host que se está administrando, por ultimo
     * actualiza los archivos de demonios o archivos.
     *
     * @param type tipo de item a almacenar: 0:demonio, 1:archivo
     * @param params parametros para la creacion del item a agregar
     */
    public void addItem(int type, String... params) {
        if (type == 0) {
            if (params.length == 5) {
                Service newService = new Service(host.getHostName(), params[0], params[1], params[2], params[3], params[4], "00:00:00");
                if (!itemExists(0, newService)) {
                    host.getServiceList().add(newService);
                }
                XMLParser.getInstance().writeServiceItems("/ring/files/", host.getHostName(), host.getServiceList());
                System.out.println("Servicio");
            }
        } else if (type == 1) {
            if (params.length == 2) {
                ConfigFile newFile = new ConfigFile(host.getHostName(), params[0], params[1]);
                if (!itemExists(1, newFile)) {
                    host.getFileList().add(newFile);
                }
                XMLParser.getInstance().writeFileItems("/ring/files/", host.getHostName(), host.getFileList());
                System.out.println("file");
            }
        }
    }

    /**
     * *Verifica si un elemento ya existe en las listas de demonios o archivos.
     *
     * @param type tipo de elemento (0:demonio, 1:archivo)
     * @param item elemento a verificar
     * @return booleano indicando si el elemento existe (true) o no (false) *
     */
    public boolean itemExists(int type, Object item) {
        Iterator iter;
        host.getFileList().iterator();
        if (type == 0) {
            iter = host.getServiceList().iterator();
            while (iter.hasNext()) {
                if (((Service) iter.next()).getDaemonName().equals(((Service) item).getDaemonName())) {
                    return true;
                }
            }
        } else if (type == 1) {
            iter = host.getFileList().iterator();
            while (iter.hasNext()) {
                if (((ConfigFile) iter.next()).getName().equals(((ConfigFile) item).getName())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * metodo con parametros opcionales que actualiza la informacion de un item
     * existente en la lista de demonios o de archivos del host que se está
     * administrando, por ultimo actualiza los archivos de demonios o archivos.
     *
     * @param type tipo de item a actualizar: 0:demonio, 1:archivo
     * @param index indice del objeto a actualizar
     * @param params parametros para la creacion del nuevo item que se usara
     * como reemplazo.
     */
    public void updateItem(int type, int index, String... params) {
        if (type == 0) {
            if (params.length == 5) {
                Service newService = new Service(host.getHostName(), params[0], params[1], params[2], params[3], params[4], "00:00:00");
                host.getServiceList().set(index, newService);
                XMLParser.getInstance().writeServiceItems("/ring/files/", host.getHostName(), host.getServiceList());
            }
        } else if (type == 1) {
            if (params.length == 2) {
                ConfigFile newFile = new ConfigFile(host.getHostName(), params[0], params[1]);
                host.getFileList().set(index, newFile);
                System.out.println("out:" + XMLParser.getInstance().writeFileItems("/ring/files/", host.getHostName(), host.getFileList()));
            }
        }
    }

    /**
     * elimina un item de la lista de demonios o de archivos del host que se
     * está administrando, por ultimo actualiza los archivos de demonios o
     * archivos.
     *
     * @param type tipo de item a eliminar: 0:demonio, 1:archivo
     * @param index indice del objeto a eliminar
     */
    public void removeItem(int type, int index) {
        if (type == 0) {
            host.getServiceList().remove(index);
            XMLParser.getInstance().writeServiceItems("/ring/files/", host.getHostName(), host.getServiceList());
        } else if (type == 1) {
            host.getFileList().remove(index);
            XMLParser.getInstance().writeFileItems("/ring/files/", host.getHostName(), host.getFileList());
        }
    }
}
